//======================================================================================================================
// 2007 Copyright Mystic Lake Software
//
// This file is part of The Ham Radio Network.
//
// The Ham Radio Network is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// The Ham Radio Network is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//======================================================================================================================
//
//     Author: Rudyard Merriam
//
//      $Id: nibbletone.cpp 6 2007-10-04 07:01:34Z k5rud@arrl.net $
//
//======================================================================================================================
//
#include <iostream>
#include <fstream>
#include <iomanip>
#include <iterator>
#include <algorithm>
#include <string>
using namespace std;

#include <stdio.h>
#include <fcntl.h>
#include <io.h>
//----------------------------------------------------------------------------------------------------------------------
// Convert a character into its numeric nibble value
char char2value(const char& ch)
{
    char nibble = (ch - '0');
    if (nibble > 9)
    {
        nibble = ch - 'a' + 10;
    }
    return nibble;
}
//----------------------------------------------------------------------------------------------------------------------
class NibbleToneEncode
{
public:
    NibbleToneEncode(const int& tones) : mPrevTone(8), mNumTones(tones) { }

    void operator()(const char& ch)
    {
        char tone = (mPrevTone + 2 + char2value(ch)) % mNumTones;
        mPrevTone = tone;

        cout << char(tone + 'A');
    }

    int mPrevTone;
    int mNumTones;
};
//----------------------------------------------------------------------------------------------------------------------
class NibbleToneDecode
{
public:
    NibbleToneDecode(const int& tones) : mPrevTone(8), mNumTones(tones) { }

    void operator()(const char& ch)
    {
        char tone = ch - 'A';

        int nibble = (tone - mPrevTone - 2 + mNumTones) % mNumTones;
        mPrevTone = tone;
        cout << nibble;
    }

    int mPrevTone;
    int mNumTones;
};
//----------------------------------------------------------------------------------------------------------------------
typedef istreambuf_iterator<char> char_in;
//==========================================================================================================================
int main(int argc, char *argv[ ])
{
    if (argc == 2)
    {
        if (argv[1][0] == 'E')
        {

            _setmode(_fileno(stdin), _O_BINARY);
            NibbleToneEncode nte(18);
            for_each((char_in(cin)), char_in(), nte);
        }
        else if (argv[1][0] == 'D')
        {
            _setmode(_fileno(stdout), _O_BINARY);
            NibbleToneDecode ntd(18);
            hex(cout);
            for_each((char_in(cin)), char_in(), ntd);
        }
    }
    else
    {
        cerr << "(E)ncode or (D)ecode option missing" << endl;
    }
}